﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tosi
{
    class Light
    {
        private int id;
        private Junction myJunction;
        public Street myStreet;
        private int state;  //1-piros, 0-zold
        private int priority;
        public double[] priorityWeights;
        public int[] greenRules;
        public int[] redRules;
        private int stationaryCars;
        private double streetLoad;
        private int time;

        public Light(int idd, Street myStr)
        {
            id = idd;
            state = 1;
            myStreet = myStr;
            priorityWeights = new double[6];
            for (int i = 0; i < 6; i++) {
                priorityWeights[i] = 1;
            }
            greenRules = new int[3];
            redRules = new int[3];
            priority = 0;
            time = 1;
            System.Threading.Thread.Sleep(10);
        }
        public int getState()
        {
            return state;
        }
        public bool isRed() {
            return state == 1;
        }
        public void setMyJunction(ref Junction my) {
            myJunction = my;
        }
        public void setLight(int stat)
        {
            //if (stat == 0)
            //    priority += 300;
            state = stat;
            time = 0;
            Var.gr.setLight(id, state);
        } 
        public void setLight() {
            if (amITheOne() == true)
            {
                state = 0;
            }
            else state = 1;
            time = 1;
            Var.gr.setLight(id, state);
            /*if(id==20)Console.Write("Changed to {0}", stat);
            time = 1;
            state = stat;
            Var.gr.setLight(id, state);*/
        }
        public void initPriority() {
            if (state == 1)
            {
                priority += (int)(redRule1() * priorityWeights[0]);
                priority += (int)(redRule2() * priorityWeights[1]);
                priority += (int)(redRule3() * priorityWeights[2]);
            }
            else {
                priority += (int)(greenRule1() * priorityWeights[3]);
                priority += (int)(greenRule2() * priorityWeights[4]);
                priority += (int)(greenRule3() * priorityWeights[5]);
            }
            //Console.WriteLine("{0} -> {1} {2}", id, priority, time);
        }
        public int updatePriority()
        {
            setStationaryCars();
            setStreetLoad();
            if (myStreet.cars.Count == 0)
            {
                //Console.Write("~{0}", id);
                return 0;
            }
            int[] pr = new int[4];
            if (state == 1)
            {
                pr[0] = 100;
                pr[1] = (int)(redRule1() * priorityWeights[0]);
                pr[2] = (int)(redRule2() * priorityWeights[1]);
                pr[3] = (int)(redRule3() * priorityWeights[2]);
            }
            else
            {
                pr[0] = 0;
                pr[1] = (int)(greenRule1() * priorityWeights[3]);
                pr[2] = (int)(greenRule2() * priorityWeights[4]);
                pr[3] = (int)(greenRule3() * priorityWeights[5]);
            }
            //Console.Write("{0:D2} PR: {5:D6} \t |{1:D3} {2:D5} {3:D5} {4:D5}", id, pr[0], pr[1], pr[2], pr[3], priority);
            //Console.WriteLine(" << {0} {1} {2}", stationaryCars, streetLoad, time);
            return pr[0]+pr[1]+pr[2]+pr[3];
        }
        public int getPriority() {
            return priority;
        }
        public void setPriority() {
            priority = updatePriority();
        }
        public void resetPriority()
        {
            priority = priority % 10007;
        }
        public void initWeights(double[] w) {
            for (int i = 0; i < 6; i++) {
                priorityWeights[i] = w[i];
            }
        }
        public void setStationaryCars(int nr) {
            if (state == 1)
            {
                stationaryCars = nr;
            }
        }
        public void reduceStationaryCars() {
            if (stationaryCars != 0) stationaryCars--;
        }
        public int getStationaryCars() {
            return stationaryCars;
        }
        public void setStreetLoad(double load) {
            streetLoad = load;
        }
        public double getStreetLoad() {
            return streetLoad;
        }
        public int getTime() {
            return time;
        }
        public void incTime() {
            time++;
        }
        public void setRedR(int[] values) {
            for (int i = 0; i < 3; i++)
            {
                redRules[i] = values[i];
            }
        }
        public void setGreenR(int[] values)
        {
            for (int i = 0; i < 3; i++)
            {
                greenRules[i] = values[i];
            }
        }
        public int getId() {
            return id;
        }
        public double[] getWeights() {
            return priorityWeights;
        }
        public void setStationaryCars()
        {
            int db = 0;
            while ((db < myStreet.cars.Count) && (myStreet.cars[db].getTempSpeed() == 0))
                db++;
            stationaryCars = db;
            //Console.WriteLine("{0} -> {1}", id, stationaryCars);
        }
        public void setStreetLoad()
        {
            if (myStreet.cars.Count != 0)
                streetLoad = myStreet.cars.Count() * 100 / myStreet.getMaxCars();
            else
                streetLoad = 0;
        }
        public bool amITheOne() {
            bool yesIam = true;
            for (int i = 0; i < myJunction.inStreets.Count; i++) {
                if (myJunction.inStreets[i].getMyLight().getPriority() > priority) return false;
            }
            return yesIam;
        }

        private int greenRule1()
        {
            /*double statCars = (double)stationaryCars / Var.greenRule1_ValidCarNr;
            //Console.Write("gR1 {0}|", statCars,id);
            if (statCars < 0.8)
            {
                return (int)(statCars * 20);
            }
            else if (statCars < 1.3)
            {
                return (int)(statCars * 40);
            }
            else return (int)(statCars * 80);*/
            return stationaryCars * 40;
        }
        private int greenRule2()
        {
            /*double strLoad = streetLoad / Var.greenRule2_ValidLoad;
            //Console.Write("gR2 {0}|", strLoad);
            if (strLoad < 0.8)
            {
                return (int)(strLoad * 20);
            }
            else if (strLoad < 1.3)
            {
                return (int)(strLoad * 40);
            }
            else return (int)(strLoad * 80);*/
            return (int)streetLoad * 40;
        }
        private int greenRule3()
        {
            /*//Console.Write("gR3 {0}|", time);
            return (int)(7 * Math.Atan(12 - time) + 30);*/
            return Math.Abs(15 - time) * 100;
        }

        private int redRule1()
        {
            /*if (myStreet.cars.Count == 0)
                return 0;
            double statCars = (double)stationaryCars / Var.redRule1_ValidCarNr;
            //Console.Write("rR1 {0}|", statCars, id);
            if (statCars < 0.8)
            {
                return (int)(statCars * 20+150);
            }
            else if (statCars < 1.3)
            {
                return (int)(statCars * 40+150);
            }
            else return (int)(statCars * 80+150);*/
            return stationaryCars * 80 + 200;
        }
        private int redRule2()
        {
            /*if (myStreet.cars.Count == 0)
                return 0;
            double strLoad = streetLoad / Var.redRule2_ValidLoad;
            //Console.Write("rR2 - {0} | ", strLoad);
            if (strLoad < 0.8)
            {
                return (int)(strLoad * 20+150);
            }
            else if (strLoad < 1.3)
            {
                return (int)(strLoad * 40+150);
            }
            else return (int)(strLoad * 80+150);*/
            return (int)(streetLoad * 80) + 200;
        }
        private int redRule3()
        {
            //Console.WriteLine("rR3 {0}|", time);
            //return (int)(2 * (Math.Pow(time, 1.6)));
            return time * 5 + 200;
        }

    }
}
